package bmechat.client;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

/**
 * The ServerMessageReader reads input from the server on the clientside, and parses server-to-client commands.
 * @author david
 */
public class ServerMessageReader implements Runnable {

    private BufferedReader reader;
    private boolean stop = false;
    private Client client;

    /**
     * Create a new ServerMessageReader.
     * @param is An Inputstream with the server-to-client messages.
     * @param client The Client that is connected to the server.
     */
    public ServerMessageReader(InputStream is, Client client) {
        reader = new BufferedReader(new InputStreamReader(is));
        this.client = client;
    }

    /**
     * Start reading messages from the server, and process them.
     */
    public void run() {
        try {
            while (!stop) {
                String input = reader.readLine();
                processServerMessage(input);
            }
        } catch (IOException e) {
            if (!stop) {
                client.addToChatLog("Error while reading from server!");
            }
        }
    }

    /**
     * Check if the message is a command. If so, the command gets parsed.
     * @param message The server-to-client message.
     */
    private void processServerMessage(String message) {
        if (message.startsWith("#")) {
            processSettingsMessage(message);
        } else {
            client.addToChatLog("> " + message);
        }
    }

    /**
     * Parses a command message and calls the appropriate method.
     * @param message The command message.
     */
    private void processSettingsMessage(String message) {
        try {
            if (message.equals("#disconnect")) {
                client.disconnect(false);
            }
            if (message.startsWith("#clientlist")) {
                parseClientList(message);
            }
            if (message.startsWith("#clientquit")) {
                otherClientQuits(message);
            }
            if (message.startsWith("#clientjoin")) {
                otherClientJoins(message);
            }
            if (message.startsWith("#clientchange=") || message.startsWith("#clientchange ")) {
                changeName(message);
            }
            if (message.startsWith("#clientchangedname")){
                clientChangedName(message);
            }
            if (message.startsWith("#admin")) {
                adminLoggedIn(message);
            }
            if (message.startsWith("#lmgtfy")) {
                googleIt(message);
            }
            if (message.startsWith("#transferFile")) {
                receiveFile(message);
            }
            if (message.startsWith("#initializeSend")) {
                sendFile(message);
            }
        } catch (Exception ex) {
            client.addToChatLog("Error while parsing server command: " + message + " (Error: " + ex.getMessage() + ")");
            ex.printStackTrace();
            ;
        }
    }

    /**
     * Stop reading from the server.
     */
    public void stop() {
        stop = true;
    }

    /**
     * Convert the clientlist String that was received from the server to a List of Strings.
     * @param message A string representation of the clientlist, e.g. #clientlist = 3|David|Pinky|Teh_Pwnerer|
     */
    private void parseClientList(String message) {
        String data = getSettingsArgument(message);

        int numClients;
        List<String> clientList = new ArrayList();
        StringTokenizer tok = new StringTokenizer(data, "|");
        numClients = Integer.parseInt(tok.nextToken());
        while (tok.hasMoreElements()) {
            String otherClient = tok.nextToken();
            clientList.add(otherClient);
        }

        client.setNumberOfClientsOnServer(numClients);
        client.setListOfClientsOnServer(clientList);
    }

    /**
     * Another client disconnects from the server.
     * @param message The #clientquit command message
     */
    private void otherClientQuits(String message) {
        String otherClient = getSettingsArgument(message);
        client.addToChatLog("Client Quits! (" + otherClient + ")");
        client.requestNewClientList();

    }

    /**
     * Another client joins the server.
     * @param message The #clientjoin command message
     */
    private void otherClientJoins(String message) {
        String otherClient = getSettingsArgument(message);
        client.addToChatLog("Client Joins! (" + otherClient + ")");
        client.requestNewClientList();
    }

    /**
     * The server asks the client to change his name.
     * @param message The #clientchange command message.
     */
    private void changeName(String message) {
        String newName = getSettingsArgument(message);
        client.setName(newName);
        client.requestNewClientList();
    }

    /**
     * Another client changed its name.
     * @param message The #clientchangedname command message.
     */
    private void clientChangedName(String message) {
        String arg = getSettingsArgument(message);
        client.requestNewClientList();
        int barIndex = arg.indexOf("|");
        if (barIndex >= 0) {
            String oldName = arg.substring(0, barIndex);
            String newName = arg.substring(barIndex + 1);
            client.addToChatLog(oldName + " changed his nickname to " + newName);
        }
    }

    /**
     * A Client logged in as Admin.
     * @param message The #admin command message.
     */
    private void adminLoggedIn(String message) {
        String admin = getSettingsArgument(message);
        client.requestNewClientList();
        client.setAdmin(true);
        client.addToChatLog(admin + " logged in as Admin");
    }

    private void googleIt(String message) {
        try {
            int equalsIndex = message.indexOf("=");
            if (equalsIndex == -1) {
                throw new IllegalArgumentException("Bad request! Operation will be canceled.");
            }

            URI location = URI.create(message.substring(equalsIndex + 1).trim());
            java.awt.Desktop browser = java.awt.Desktop.getDesktop();
            browser.browse(location);
        } catch (MalformedURLException ex) {
            client.addToChatLog("Malformed url: " + message.substring( message.indexOf("=")+ 1));
        }catch (IOException ex) {
            client.addToChatLog("Could not open browser. Use this url: " + message.substring( message.indexOf("=")+ 1));
        }
    }

    private void receiveFile(String message) {
        try {
            int equalsIndex1 = message.indexOf("=");
            int equalsIndex2 = message.indexOf("\\");
            int equalsIndex3 = message.indexOf("/");
            if (equalsIndex1 == -1 || equalsIndex2 == -1 || equalsIndex3 == -1) {
                throw new IllegalArgumentException("Bad request! Operation will be canceled.");
            }

            int filesize = Integer.parseInt(message.substring(equalsIndex1 + 1, equalsIndex2).trim());
            String sender = message.substring(equalsIndex2 + 1, equalsIndex3).trim();
            String filename = message.substring(equalsIndex3+1).trim();
            int accept = JOptionPane.showConfirmDialog(null, sender + " wants to send you the following file: \n" + filename + " (" + filesize + "B)");
            if(accept == JOptionPane.OK_OPTION){
                new File("C:\\BME-Chat").mkdir();
                client.receiveFile(filesize, sender, "C:/BME-Chat/"+filename);

            } else{
                client.addToChatLog("You did not accept the file transfer.");
            }
        } catch (Exception ex) {
            client.addToChatLog("Filetransfer failed.");
        }
    }

    private void sendFile(String message) {
        client.sendFile();
    }

    /**
     * Get the command argument from a command message.
     * @param message A server-to-client command message.
     * @return The argument of the command.
     * @throws IllegalArgumentException
     */
    private String getSettingsArgument(String message) throws IllegalArgumentException {
        int equalsIndex = message.indexOf('=');
        if (equalsIndex == -1) {
            throw new IllegalArgumentException("no '=' was found. ");
        }
        return message.substring(equalsIndex + 1).trim();
    }
}
